﻿/* Copyright 2011 Michiel Fortuin
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * */

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Reflection;

namespace sharplog
{
	/// <summary>
	/// the level of severity
	/// </summary>
	public enum Level
	{
		Emergency = 0,
		Alert = 1,
		Critical = 2,
		Error = 3,
		Warning = 4,
		Notice = 5,
		Information = 6,
		Debug = 7,
	}

	/// <summary>
	/// facility from where a message comes from
	/// </summary>
	public enum Facility
	{
		Kernel = 0,
		User = 1,
		Mail = 2,
		Daemon = 3,
		Auth = 4,
		Syslog = 5,
		Lpr = 6,
		News = 7,
		UUCP = 8,
		Clock = 9,
		Auth2 = 10,
		FTP = 11,
		NTP = 12,
		LogAudit = 13,
		LogAlert = 14,
		Clock2 = 15,
		Local0 = 16,
		Local1 = 17,
		Local2 = 18,
		Local3 = 19,
		Local4 = 20,
		Local5 = 21,
		Local6 = 22,
		Local7 = 23
	}

	/// <summary>
	/// structure with a combined formater and transporter.
	/// </summary>
	public class Destination
	{
		public Sender Transport { get; set; }
		public Formater Formater { get; set; }

		public Destination()
		{
		}

		public Destination(Sender transport, Formater formater)
		{
			this.Transport = transport;
			this.Formater = formater;
		}
	}

	/// <summary>
	/// Main log class
	/// </summary>
	public class Log
	{
		#region singleton

		private static Log _instance;

		public static Log Instance
		{
			get { return _instance; }
			set { _instance = value; }
		}

		/// <summary>
		/// creates the default log in instance
		/// </summary>
		public static void CreateDefaultLog()
		{
			Assembly asm = Assembly.GetEntryAssembly();
			string AppName = string.Empty;
			if (asm == null)
			{
				//Running real live
				AppName = asm.GetName().Name;
			}
			else
			{
				//Testing with NUnit
				AppName = "SharpLogTest";
			}

			int p = (int) Environment.OSVersion.Platform;
			if ((p == 4) || (p == 6) || (p == 128))
			{
				// running *nux
				_instance =
					new Log(new Destination(new SenderUdp(new IPEndPoint(IPAddress.Loopback, 514)), new Syslog(AppName)),
					        new Destination(new SenderStream(Console.OpenStandardOutput()), new TextFormater(AppName)));
			}
			else
			{
				// running Windows
				_instance =
					new Log(new Destination(new WinEventsLogSender(AppName), new WinEventsLogFormater()),
					        new Destination(new SenderStream(Console.OpenStandardOutput()), new TextFormater(AppName)));
			}
		}

		/// <summary>
		/// Sends a message to a log server
		/// </summary>
		/// <param name="level">The level of the message</param>
		/// <param name="facility">The facility from where it is send</param>
		/// <param name="messageId">The message id that must be send with the message</param>
		/// <param name="message">The message. This is optional as the protocol describes it.</param>
		public static void SendMessage(Level level, Facility facility, string messageId, string message = "")
		{
			if(_instance == null)
			{
				CreateDefaultLog();
			}
			_instance.SendMessage2(level, facility, messageId, message);
		}

		#endregion

		private List<Destination> destinations = new List<Destination>();

		/// <summary>
		/// To which it must send the log messages
		/// </summary>
		public List<Destination> Destinations
		{
			get { return destinations; }
			set { destinations = value; }
		}

		/// <summary>
		/// Creates a log client
		/// </summary>
		/// <param name="transport">The transport protocol that should be used.</param>
		/// <param name="formater">The formater used to create the data to be send.</param>
		public Log(params Destination[] destination)
		{
			this.destinations.AddRange(destination);
		}

		/// <summary>
		/// Creates a log client
		/// </summary>
		/// <param name="transport">The transport protocol that should be used.</param>
		/// <param name="formater">The formater used to create the data to be send.</param>
		public Log(Sender transport, Formater formater)
		{
			destinations.Add(new Destination(transport, formater));
		}

		/// <summary>
		/// Sends a message to a log server
		/// </summary>
		/// <param name="level">The level of the message</param>
		/// <param name="facility">The facility from where it is send</param>
		/// <param name="messageId">The message id that must be send with the message</param>
		/// <param name="message">The message. This is optional as the protocol describes it.</param>
		public void SendMessage2(Level level, Facility facility, string messageId, string message = "")
		{
			foreach (Destination destination in Destinations)
			{
				destination.Transport.SendMessage(destination.Formater.ConstructMessage(level, facility, messageId, message));
			}
		}
	}
}